#include "header.h"
#include <iostream>
#include <new>

ServerMgr::ServerMgr() {
	head = NULL;
	report = false;
	count = 0;
}

ServerMgr::~ServerMgr() {
	Snode *ptr = NULL;

	if (true) {
		std::cout << "=============Server Statistics===========" << std::endl;
	}

	while (head != NULL) {
		ptr=head;
		head=head->next;
		float avgNumInServer;
		float avgServiceTime;
		try{
			avgNumInServer = 1 - (ptr->st).idleTime/(ptr->st).totalTime;
			avgServiceTime = (ptr->st).totalDequeuedServiceTime/(ptr->st).deserverCounter;
		}
		catch (...) {
			throw MATHERROR_ST;
		}
		std::cout << "Server " << (ptr->id) << ':' << std::endl;
		std::cout << "\tEnserver.Counter = " << ((ptr->st).deserverCounter + ((ptr->idle)?0:1)) << std::endl;
		std::cout << "\tDeserver.Counter = " << ((ptr->st).deserverCounter) << std::endl;
		std::cout << "\tavg.Num.In.Server= " << avgNumInServer<< std::endl;
		std::cout << "\tavg.Service.Time = " << avgServiceTime << std::endl;

		try {
			if (ptr->customer != NULL) {
				delete ptr->customer;
			}
			delete ptr;
		}
		catch (...) {
			throw MEMERROR_FREE;
		}
	}
}

unsigned ServerMgr::getCount() {
	return count;
}

double defaultServiceDuration() {
	throw LOGICERROR_SERVICEDURATION;
	return 1;
}

Server ServerMgr::newServer() {
	Snode *ptr = NULL;
	try {
		ptr = new Snode;
	}
	catch (std::bad_alloc &e) {
		throw MEMERROR_ALLOC;
	}
	ptr->customer = NULL;
	ptr->idle = true;
	ptr->id = count;
	ptr->serviceDuration = &defaultServiceDuration;
	(ptr->st).deserverCounter = 0;
	(ptr->st).totalDequeuedServiceTime = 0;
	(ptr->st).idleTime = 0;
	(ptr->st).totalTime = 0;
	ptr->report = &report;

	ptr->next=head;
	head=ptr;

	count++;

	Server r;
	r.data = ptr;
	return r;
}

Server ServerMgr::getServer(unsigned i) {
	unsigned j=0;
	Snode *ptr;
	if (i >= count ) {
		throw LOGICERROR_INVAILDID;
	}
	ptr = head;
	if ( ptr == NULL ) {
		throw LOGICERROR_LINKTAB;
	}
	for (j = count; j != i + 1; j--) {
		ptr = ptr -> next;
		if (ptr == NULL) {
			throw LOGICERROR_LINKTAB;
		}
	}
	Server r;
	r.data = ptr;
	return r;
}

double Server::serviceDuration() {
	if ( data == NULL ) {
		throw LOGICERROR_NULLSERVER;
	}
	return data->serviceDuration();
}

void Server::serviceDurationFunc(double (*func)()) {
	data->serviceDuration = func;
}

void Server::term(double time) {
	eventHandler(time);
}

void Server::eventHandler(double time) {
	if (time < (data->st).totalTime) {
		throw LOGICERROR_TIME;
	}
	if ( data->idle ) {
		(data->st).idleTime += (time - (data->st).totalTime);
	}
	(data->st).totalTime = time;
}

Server::Server() {
	data = NULL;
}

bool Server::isIdle() {
	if ( data == NULL ) {
		throw LOGICERROR_NULLSERVER;
	}
	return data->idle;
}

unsigned Server::getId() {
	if ( data == NULL ) {
		throw LOGICERROR_NULLSERVER;
	}
	return data->id;
}

void Server::enserver(entity e, double time) {
	if ( data == NULL ) {
		throw LOGICERROR_NULLSERVER;
	}
	if ( data->customer != NULL ) {
		throw LOGICERROR_ENSERVERNONEMPTYSERVER;
	}
	eventHandler(time);
	e.enserver() = time;
	e.serverId() = data->id;
	data->idle = false;
	data->customer = new entity;
	*(data->customer) = e;

	if (*(data->report)) {
		std::cout << "Enserver Server:  " << (data->id) << "\tentity: " << e.getId() << "\ttime = " << time << std::endl;
	}
}

entity Server::deserver(double time) {
	if ( data == NULL ) {
		throw LOGICERROR_NULLSERVER;
	}
	if ( data->customer == NULL ) {
		throw LOGICERROR_EMPTYSERVER;
	}
	entity r;
	r = *(data->customer);
	try {
		delete data->customer;
	}
	catch (...) {
		throw MEMERROR_FREE;
	}
	eventHandler(time);
	data->customer = NULL;
	data->idle = true;
	r.deserver() = time;
	(data->st).totalDequeuedServiceTime += r.deserver() - r.enserver();
	if (*(data->report)) {
		std::cout << "Deserver Server:  " << (data->id) << "\tentity: " << r.getId() << "\ttime = " << time << std::endl;
	}
	(data->st).deserverCounter ++;
	return r;
}

entity Server::getEntity() {
	if ( data == NULL ) {
		throw LOGICERROR_NULLSERVER;
	}
	if ( data->customer == NULL ) {
		throw LOGICERROR_EMPTYSERVER;
	}
	return *(data->customer);
}

void Server::enserver(Queue q, double time) {
	this->enserver(q.dequeue(time),time);
}

void ServerMgr::term(double time) {
	Snode *ptr;
	Server s;
	for (ptr = head; ptr != NULL; ptr = ptr->next) {
		s.data = ptr;
		s.term(time);
	}
}

unsigned ServerMgr::totalServed() {
	unsigned i = 0;
	Snode * ptr = NULL;

	for (ptr = head; ptr != NULL; ptr = ptr -> next) {
		i += (ptr->st).deserverCounter;
	}
	return i;
}

double ServerMgr::avgServiceTime() {
	unsigned i = 0;
	double j = 0 ;
	Snode * ptr = NULL;
	for (ptr = head; ptr != NULL; ptr = ptr -> next) {
		i += (ptr->st).deserverCounter;
		j += (ptr->st).totalDequeuedServiceTime;
	}
	return j/i;
}
